Skip to content

feat(governance): Google ADK adapter#362

Open
aditik0303 wants to merge 9 commits into
mainfrom
feat/governance-google-adk
Open

feat(governance): Google ADK adapter#362
aditik0303 wants to merge 9 commits into
mainfrom
feat/governance-google-adk

Conversation

@aditik0303

@aditik0303 aditik0303 commented Jun 24, 2026

Copy link
Copy Markdown

Summary

Adds a Google ADK governance adapter to uipath-google-adk. It lets UiPath governance evaluate what a Google ADK agent does at the model and tool level, and block disallowed actions, without the agent author writing governance code. This package contains only the ADK-specific bridge.

What it does

  • Detects a google.adk.agents.BaseAgent. ADK agents are executed by a Runner that holds its own reference to the agent, so the adapter installs governance directly onto each LlmAgent's native callback attributes (mutating them in place) and returns the original agent rather than a proxy.

  • Maps each native callback to a governance check:

    Google ADK callback Governance hook
    before_model_callback BEFORE_MODEL
    after_model_callback AFTER_MODEL
    before_tool_callback TOOL_CALL
    after_tool_callback AFTER_TOOL
  • Enforces by letting a GovernanceBlockException (raised on a DENY decision) propagate, stopping the model call or tool. Any other error inside a governance hook is logged and swallowed, so a governance failure cannot break an otherwise-healthy agent run.

  • Installed by the runtime factory: passing an evaluator to new_runtime wires governance onto the resolved agent in place. No adapter registry, no entry point, no import-time registration.

What it does not do

  • Does not fire agent-level boundaries (BEFORE_AGENT / AFTER_AGENT); those are owned by the governance host.
  • Does not depend on platform, auth, transport, or runtime internals — only on the shared governance contracts in uipath-core.

aditik0303 and others added 2 commits June 22, 2026 23:09
Installs governance on each LlmAgent's native callbacks (before/after_model_callback -> BEFORE/AFTER_MODEL, before/after_tool_callback -> TOOL_CALL/AFTER_TOOL) in place, walking the sub_agents tree.

Self-registers via the uipath.governance.adapters entry point; unit-tested and cloud-verified end to end (CodedAgent03). BEFORE/AFTER_AGENT remain owned by the uipath-runtime wrapper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…, framework-only can_handle)

Mirror radu's LangChain-adapter review across the Google ADK adapter:
- __init__: drop the import-time registration side-effect; registration only via the uipath.governance.adapters entry point.
- can_handle: claim only a real google.adk BaseAgent; remove the duck-typed (name + model-callback / sub_agents) fallback.
- docstring: 'governance host' instead of uipath-runtime internals.
- tests: can_handle uses a real LlmAgent; duck-typed look-alikes are now rejected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 24, 2026 12:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a governance adapter for Google ADK so the governance host can attach deep hooks (BEFORE_MODEL / AFTER_MODEL / TOOL_CALL / AFTER_TOOL) to ADK LlmAgent callback slots via entry-point discovery (no import-time registration).

Changes:

  • Introduces GoogleADKAdapter and GovernanceCallbacks to install/remove governance callbacks across an ADK agent tree.
  • Adds adapter registration function exposed via the uipath.governance.adapters entry point.
  • Adds unit tests covering can_handle, attach/detach behavior, payload extraction, and enforcement semantics.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/uipath-google-adk/tests/governance/test_adapter.py New tests for adapter detection, callback wiring, payload extraction, and exception semantics.
packages/uipath-google-adk/tests/governance/init.py Test package marker for governance tests.
packages/uipath-google-adk/src/uipath_google_adk/governance/adapter.py New ADK governance adapter implementation and callback payload extraction logic.
packages/uipath-google-adk/src/uipath_google_adk/governance/init.py Entry-point registration function for the governance adapter (idempotent, no import-time mutation).
packages/uipath-google-adk/pyproject.toml Adds uipath-core dependency and the uipath.governance.adapters entry point.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/uipath-google-adk/tests/governance/test_adapter.py Outdated
aditik0303 and others added 7 commits June 24, 2026 18:41
- Text-cap comment: refer to the governance host, not the uipath-runtime wrapper constant.
- Test docstring: note can_handle uses a real google.adk LlmAgent (isinstance detection); only payload shapes are faked.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…K adapter

Record that LlmRequest/LlmResponse/content/parts are read via getattr
rather than isinstance on ADK's typed models, to avoid hard-coupling to
google-adk internals and to let tests duck-type payloads without the
package installed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Core PR #1761 removed BaseAdapter from uipath-core. Migrate to the
factory-evaluator pattern (matching #899):

- governance/adapter.py -> callbacks.py: replace the BaseAdapter subclass
  (name/can_handle/attach/detach) with module-level install_governance()
  that installs governance on each LlmAgent's native *_callback slots
  (walking sub_agents); keep GovernanceCallbacks + the callback helpers;
  drop the detach-only _remove_callbacks. File named for its seam
  (callbacks), like LangChain's callbacks.py.
- runtime/factory.py: new_runtime reads `evaluator` from kwargs and
  calls install_governance before building the Runner.
- governance/__init__.py: drop register_governance_adapter + registry
  import; expose install_governance. No import-time side effects.
- pyproject.toml: remove the uipath.governance.adapters entry point.
- tests (test_adapter.py -> test_callbacks.py): drop can_handle/attach/
  detach; cover install_governance + factory wiring.

ruff + mypy clean; 21 governance tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ool walk

Review findings (Viswa) for PR #362:

- Drop the per-callbacks uuid trace_id (identical for every call); trace
  correlation is owned by the layer below, matching LangChain. Requires
  uipath-core >= 0.5.20, which removed trace_id from EvaluatorProtocol —
  bumped in the lock.
- Count llm/tool calls only after governance passes: a DENY raised before
  the bump, inflating the counter on blocked calls.
- Follow AgentTool-wrapped agents: an agent exposed as a tool lives in
  ``tools`` (on ``tool.agent``), not ``sub_agents``, so the walk missed it.
- Refresh governance metadata on cached-agent reuse: the factory caches
  agents by entrypoint, so a second new_runtime with a new session_id would
  otherwise keep the first run's session_id (install was a no-op). Added
  GovernanceCallbacks.rebind() + _find_governance_callbacks().
- Log (not silently drop) when the tree walk hits the node cap.
- Cap _stringify output so an oversized tool result / args / response
  can't hand a multi-megabyte string to the evaluator.
- Trailing newline (W292).

Tests: added AgentTool-walk, cached-agent rebind, and no-inflation-on-block
coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow-up to the #362 review pass — the earlier commit covered AgentTool walk,
_stringify cap, cached-agent rebind, trace_id drop, and the cap warning; these
are the rest of page 6:

- callbacks.py:249 (Major) — before_tool no longer passes tool args uncapped.
  New _cap_args bounds the payload: within budget the dict passes through
  unchanged (per-key rules still work); once its serialized size exceeds the
  cap it is replaced with a single capped {"_truncated": ...}. Contrast with
  after_tool, which already capped its result.
- test_callbacks.py (Minor) — the tree test now also asserts the container
  agent is NOT decorated; added a huge-args cap test. (Double-attach with a
  pre-existing user callback is already covered by
  test_install_governance_preserves_existing_callback_and_runs_first.)

Acknowledged, unchanged (flagged as follow-ups):
- callbacks sync-only (Major): making governance async is a protocol-wide
  change (the evaluator is sync) — deferred, not one-off here.
- _session_state accumulation across cached-agent reuse (Minor): fixed by the
  rebind added in the earlier commit (rebind resets the counters). Per-task
  safety for ParallelAgent's concurrent callbacks is a known limitation.
- LIFO cap ordering (Minor): the cap now logs; which nodes are dropped past
  the cap is non-deterministic but all found nodes are governed.

Tests: 66 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Same pre-existing CI-lint failure (mypy runs over tests):
- FakeEvaluator evaluate_* -> (self, *args, **kwargs) -> Any so it satisfies
  EvaluatorProtocol; bare dict -> dict[str, Any].
- moved the Boom test-double arg-type ignore onto the reported line;
  func-returns-value ignores on the return-None pass-through asserts.

mypy . clean (26 files); ruff + 66 tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New-code coverage ~89% -> over the 90% gate. Added non-block swallow on the
model/tool callbacks and _content_text / _cap_args / _stringify helper edges.
governance/callbacks.py: 89% -> 96%.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Jul 1, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants